﻿using System;
using System.Collections.Generic;
using System.Linq;
using DocumentFormat.OpenXml;
using D = DocumentFormat.OpenXml.Drawing;
using P = DocumentFormat.OpenXml.Presentation;
using PK = DocumentFormat.OpenXml.Packaging;
using Fantom.Helper;
using Fantom.Drawing;

namespace Fantom.Drawing
{
	internal static class ColorLoader
	{
		public static BaseColor GetDefaultColor
			(PK.SlidePart sldpart, ITheme theme, OpenXmlElement color, IMediaManager mediaManager)
		{
			if (color is D.SchemeColor)
			{
				var attr = (color as D.SchemeColor).Val.ToString();
				var type = ThemeColorTypeHelper.GetColorType(attr);
				return theme.Colors[type];
			}
			else if (color is D.RgbColorModelHex)
			{
				return new SolidColor((color as D.RgbColorModelHex).Val.Value);
			}
			else if (color is D.Blip)
			{
				var uris = from rp in sldpart.Parts where (color as D.Blip).Embed == rp.RelationshipId select rp.OpenXmlPart.Uri;
				var uri = uris.First();

				return new BitmapColor(mediaManager.CreateMedia(uri));
			}
			else
				return null;
		}

		public static BaseColor GetDefaultFill
			(PK.SlidePart sldpart, ITheme theme, OpenXmlElement style, IMediaManager mediaManager)
		{
			if (style == null) return null;

			var mark = "fillRef";
			var rst = (from fillnode in style
					   where fillnode.LocalName.EndsWith(mark)
					   select fillnode);

			var fill = rst.FirstOrDefault();
			if (fill == null) return null;

			var color = fill.FirstChild;
			return GetCustomColor(sldpart, theme, color, mediaManager);
		}

		public static BaseColor GetDefaultLine
			(PK.SlidePart sldpart, ITheme theme, OpenXmlElement style, IMediaManager mediaManager)
		{
			if (style == null) return null;

			var mark = "lnRef";
			var rst = (from node in style
					   where node.LocalName.EndsWith(mark)
					   select node);

			var line = rst.FirstOrDefault();
			if (line == null) return null;

			var color = line.FirstChild;
			return GetCustomColor(sldpart, theme, color, mediaManager);

		}


		public static BaseColor GetCustomColor(OpenXmlElement color)
		{
			return new SolidColor((color as D.RgbColorModelHex).Val.Value);
		}

		public static BaseColor GetCustomColor(ITheme theme, OpenXmlElement color)
		{
			if (color is D.RgbColorModelHex)
			{
				return new SolidColor((color as D.RgbColorModelHex).Val.Value);
			}
			else if (color is D.SchemeColor)
			{
				return GetSchemeColorFromDXMLNode(theme, color as D.SchemeColor);
			}
			else if (color is P.HslColor)
			{
				return GetHSLColorFromDXMLNode(color as P.HslColor);
			}
			throw new Exception("不明颜色节点");

		}

		/// <summary>
		/// 导入颜色。
		/// </summary>
		public static BaseColor GetCustomColor
			(PK.SlidePart sldpart, ITheme theme, OpenXmlElement color, IMediaManager mediaManager)
		{
			if (color is D.RgbColorModelHex)
			{
				return SolidColor.FromHex((color as D.RgbColorModelHex).Val.Value);
			}
			else if (color is D.SchemeColor)
			{
				return GetSchemeColorFromDXMLNode(theme, color as D.SchemeColor);
			}
			else if (color is D.Blip)
			{
				var uris = from rp in sldpart.Parts where (color as D.Blip).Embed == rp.RelationshipId select rp.OpenXmlPart.Uri;
				var uri = uris.First();

				return new BitmapColor(mediaManager.CreateMedia(uri));
			}
			else if (color is P.HslColor)
			{
				return GetHSLColorFromDXMLNode(color as P.HslColor);
			}
			throw new Exception("不明颜色节点");

		}

		/// <summary>
		/// 导入颜色。
		/// </summary>
		public static BaseColor GetCustomFill
			(PK.SlidePart sldpart, ITheme theme, OpenXmlElement pr, IMediaManager mediaManager)
		{
			var mark = "Fill";
			var rst = (from fillnode in pr
					   where fillnode.LocalName.EndsWith(mark)
					   select fillnode);

			var fill = rst.FirstOrDefault();
			if (fill == null) return null;

			var color = fill.FirstChild;

			return GetCustomColor(sldpart, theme, color, mediaManager);

		}


		public static BaseColor GetCustomLine
			(PK.SlidePart sldpart, ITheme theme, OpenXmlElement pr, IMediaManager mediaManager)
		{
			var mark = "ln";
			var rst = (from fillnode in pr
					   where fillnode.LocalName.EndsWith(mark)
					   select fillnode);

			var line = rst.FirstOrDefault();
			if (line == null) return null;

			return GetCustomFill(sldpart, theme, line, mediaManager);

		}


		// 从 D.SchemeColor 对象中提取指定细节颜色。
		public static SchemeColor GetSchemeColorFromDXMLNode(ITheme theme, D.SchemeColor dcolor)
		{
			var attr = dcolor.Val.ToString();
			var type = ThemeColorTypeHelper.GetColorType(attr);

			var xmod = dcolor.GetFirstChild<D.LuminanceModulation>();
			var xoff = dcolor.GetFirstChild<D.LuminanceOffset>();
			var xalp = dcolor.GetFirstChild<D.Alpha>();
			var xshd = dcolor.GetFirstChild<D.Shade>();

			var off = xoff != null ? xoff.Val.Value : Emu.Num0;
			var mod = xmod != null ? xmod.Val.Value : Emu.Num100;
			var alp = xalp != null ? xalp.Val.Value : Emu.Num0;
			var shd = xshd != null ? xshd.Val.Value : Emu.Num0;

			if (xoff != null || xmod != null)
				return SchemeColor.FromLum(theme.Colors[type], alp, mod, off, type);
			else if (xshd != null)
				return SchemeColor.FromShade(theme.Colors[type], alp, shd, type);

			return SchemeColor.FromLum(theme.Colors[type], alp, mod, off, type);
		}

		/// <summary>
		/// 从节点数据中提取正确的 HSL 变化值。
		/// </summary>
		/// <param name="dcolor"></param>
		/// <returns></returns>
		public static SolidColor GetHSLColorFromDXMLNode(P.HslColor dcolor)
		{
			var hue = 255d * dcolor.Hue.Value / Emu.TwoPi;
			var sat = 255d * dcolor.Saturation.Value / Emu.TwoPi;
			var lum = 255d * dcolor.Lightness.Value / Emu.TwoPi;
			return SolidColor.FromHSL(hue, sat, lum);
		}

	}
}
